package ca.concordia.soen6461.wichf.ui.web;

import ca.concordia.soen6461.wichf.controller.Action;
import ca.concordia.soen6461.wichf.controller.Condition;
import ca.concordia.soen6461.wichf.controller.View;
import ca.concordia.soen6461.wichf.controller.dsl.NavigationModel;
import ca.concordia.soen6461.wichf.controller.dsl.NavigationModelBuilder;
import ca.concordia.soen6461.wichf.controller.dsl.NavigationModelBuilderImpl;
import ca.concordia.soen6461.wichf.dao.PatientCartDao;
import ca.concordia.soen6461.wichf.dao.ScheduledEventDao;
import ca.concordia.soen6461.wichf.dao.mem.PatientCartMemDao;
import ca.concordia.soen6461.wichf.dao.mem.ScheduledEventMemDao;
import ca.concordia.soen6461.wichf.navigation.action.DoCancelAppointment;
import ca.concordia.soen6461.wichf.navigation.action.DoMakeAvailabilityFrom;
import ca.concordia.soen6461.wichf.navigation.action.DoMakeAvailabilityTo;
import ca.concordia.soen6461.wichf.navigation.action.DoMakeCheckupAppointment;
import ca.concordia.soen6461.wichf.navigation.action.DoMakeVisitAppointment;
import ca.concordia.soen6461.wichf.navigation.action.DoProcessPayment;
import ca.concordia.soen6461.wichf.navigation.condition.IsPaymentAccepted;
import ca.concordia.soen6461.wichf.navigation.event.BackEvent;
import ca.concordia.soen6461.wichf.navigation.event.CancelAppointmentEvent;
import ca.concordia.soen6461.wichf.navigation.event.CheckoutEvent;
import ca.concordia.soen6461.wichf.navigation.event.HomeEvent;
import ca.concordia.soen6461.wichf.navigation.event.MakeCheckupAppointmentEvent;
import ca.concordia.soen6461.wichf.navigation.event.MakeVisitAppointmentEvent;
import ca.concordia.soen6461.wichf.navigation.event.AvailabilityFromEvent;
import ca.concordia.soen6461.wichf.navigation.event.AvailabilityToEvent;
import ca.concordia.soen6461.wichf.navigation.event.UnavailabilityToEvent;
import ca.concordia.soen6461.wichf.navigation.event.PayEvent;
import ca.concordia.soen6461.wichf.navigation.event.ViewCartEvent;
import ca.concordia.soen6461.wichf.navigation.view.CartView;
import ca.concordia.soen6461.wichf.navigation.view.CheckoutView;
import ca.concordia.soen6461.wichf.navigation.view.ConfirmationView;
import ca.concordia.soen6461.wichf.navigation.view.HomeView;
import ca.concordia.soen6461.wichf.service.SchedulingService;
import ca.concordia.soen6461.wichf.service.SchedulingServiceImpl;
import ca.concordia.soen6461.wichf.ui.web.parser.AvailabilityFromEventParser;
import ca.concordia.soen6461.wichf.ui.web.parser.AvailabilityToEventParser;
import ca.concordia.soen6461.wichf.ui.web.parser.UnavailabilityToEventParser;
import ca.concordia.soen6461.wichf.ui.web.parser.BackEventParser;
import ca.concordia.soen6461.wichf.ui.web.parser.CancelAppointmentEventParser;
import ca.concordia.soen6461.wichf.ui.web.parser.CheckoutEventParser;
import ca.concordia.soen6461.wichf.ui.web.parser.HomeEventParser;
import ca.concordia.soen6461.wichf.ui.web.parser.MakeCheckupAppointmentEventParser;
import ca.concordia.soen6461.wichf.ui.web.parser.MakeVisitAppointmentEventParser;
import ca.concordia.soen6461.wichf.ui.web.parser.PayEventParser;
import ca.concordia.soen6461.wichf.ui.web.parser.ViewCartEventParser;

public class ControllerServlet extends BaseServlet {

	private static final long serialVersionUID = 4828038547925371001L;
	
	/* DAOs */
	private ScheduledEventDao scheduledEventDao = new ScheduledEventMemDao();
	private PatientCartDao patientCartDao = new PatientCartMemDao();
	
	/* Services */
	private SchedulingService schedulingService = new SchedulingServiceImpl(scheduledEventDao, patientCartDao);
	
	/* Views */
	private View<?> homeView = new HomeView(schedulingService);
	private View<?> cartView = new CartView(patientCartDao);
	private View<?> checkoutView = new CheckoutView(patientCartDao);
	private View<?> confirmationView = new ConfirmationView();
	
	/* Conditions */
	private Condition isPaymentAccepted = new IsPaymentAccepted();

	/* Actions */
	private Action cancelAppointment = new DoCancelAppointment(schedulingService);
	private Action makeVisitAppointment = new DoMakeVisitAppointment(schedulingService);
	private Action makeCheckupAppointment = new DoMakeCheckupAppointment(schedulingService);
	private Action makeAvailabiltyFrom = new DoMakeAvailabilityFrom(schedulingService);
	private Action makeAvailabiltyTo = new DoMakeAvailabilityTo(schedulingService, true);
	private Action makeUnavailabiltyTo = new DoMakeAvailabilityTo(schedulingService, false);
	private Action processPayment = new DoProcessPayment(patientCartDao);

	public ControllerServlet() {
	}

	@Override
	protected BaseEventParser<?>[] createParsers() {
		return new BaseEventParser<?>[] {
			new HomeEventParser(),
			new BackEventParser(),
			new CancelAppointmentEventParser(),
			new CheckoutEventParser(),
			new MakeVisitAppointmentEventParser(),
			new MakeCheckupAppointmentEventParser(),
			new AvailabilityFromEventParser(),
			new AvailabilityToEventParser(),
			new UnavailabilityToEventParser(),
			new PayEventParser(),
			new ViewCartEventParser()
		};
	}

	@Override
	protected ViewMapping[] createViewMappings() {
		return new ViewMapping[] {
			mapping(homeView, "/home.jsp"),
			mapping(cartView, "/cart.jsp"),
			mapping(checkoutView, "/checkout.jsp"),
			mapping(confirmationView, "/confirmation.jsp"),
		};
	}

	@Override
	protected NavigationModel createNavigationModel() {
		NavigationModelBuilder builder = new NavigationModelBuilderImpl(homeView) {
			{
				from(homeView,
					on(MakeVisitAppointmentEvent.class).perform(makeVisitAppointment).stay(),
					on(MakeCheckupAppointmentEvent.class).perform(makeCheckupAppointment).stay(),
					on(CancelAppointmentEvent.class).perform(cancelAppointment).stay(),
					on(AvailabilityFromEvent.class).perform(makeAvailabiltyFrom).stay(),
					on(AvailabilityToEvent.class).perform(makeAvailabiltyTo).stay(),
					on(UnavailabilityToEvent.class).perform(makeUnavailabiltyTo).stay(),
					on(ViewCartEvent.class).goTo(cartView)
				);
				from(cartView,
					on(CheckoutEvent.class).goTo(checkoutView),
					on(BackEvent.class).goBack(),
					on(HomeEvent.class).goHome()
				);
				from(checkoutView,
					on(PayEvent.class).provided(isPaymentAccepted).perform(processPayment).goTo(confirmationView),
					on(BackEvent.class).goBack(),
					on(HomeEvent.class).goHome()
				);
				from(confirmationView,
					on(HomeEvent.class).goHome()
				);
			}
			
		};
		return builder.getResult();
	}

}
